/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package wave;

import ast.*;
import base.TrackNode;
import base.Utilities;
import base.Wave;
import base.WaveEnvironment;
import java.util.Vector;
import java.util.Collection;
import java.util.Iterator;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Hashtable;
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import trackmsg.EchoMsg;
import trackmsg.TrackCtrlMsg;

/**
 * Xu ly systemcall cua wave . Goi 1 class chua chay hoac 1 loi goi he thong windows
 * @author Vu Duc Tiep
 */
public class ASTSysCallExecution extends WaveExecution {
    public ASTSysCallExecution(WaveHeadParser parser, WaveEnvironment waveEnv){
        super(parser, waveEnv);
    }
    /**
     * 
     * @param caller
     * @param tail  String chua duoi cua chuoi wave sau khi xu ly xong System call
     * Example: Fa=0.Fa:1=0.Fa:2=1.Fa:3=0.Fa?`dir C:'
     *          Fa=0.Fa:1=1.Fa:2=1.Fa:3=`C:\';5.Fa?`test'.Fb=5
     * bien 1: Luu gia tri offset   0:goi lenh he thong(windows)
     *                              1: Goi 1 class java khac chua chay
     *                              2: Truyền tham số cho 1 process khác qua socket (Ko phat trien o day )
     * bien 2: Luu gia tri offset   0:chay luon chuoi wave tiep theo;  
     *                              1: doi viec xu ly syscall xong moi tao. wave chay tiep
     * bien 3: Luu gia tri dau vao cho class hoac command ben ve phai 
     *                  (Neu la goi class thi phan tu dau tien Fa:3 phai co classpath)
     * Gia tri xuat ra cua chtrinh ben ve fai se duoc luu lai duoi dang String 
     *                  (Trong chtrinh duoc goi phai in ket qua ra man hinh)
     *                  Moi dong la 1 phan tu cua vector
     */ 
    public void execute(ASTSysCall caller,String tail){

        Utilities.WPPrint("Execute System call : "+ caller.getString());
        if(caller!=null && caller.jjtGetNumChildren()==2){

            if (caller.jjtGetChild(1) instanceof ASTStringConst ) {
                String sleep = ((ASTStringConst) (caller.jjtGetChild(1))).getString();
                sleep = sleep.substring(1, sleep.length()-1);
                
                if (sleep.toUpperCase().equals("SLEEP"))
                {
                    try {
                        int delay = 0;
                        if (caller.jjtGetChild(0) instanceof ASTIntConst) {
                            delay = Integer.parseInt(((ASTIntConst) (caller.jjtGetChild(0))).getString());
                        }
                        Utilities.WPPrint("SLEEP : " + delay);
                        currentThread.sleep(delay*1000);
                        
                    } catch (Exception ex) {
                        Logger.getLogger(ASTSysCallExecution.class.getName()).log(Level.SEVERE, null, ex);
                    }

                    if (waveEnv.getTrackAddress() != null && tail.equals("")) {
                        TrackNode fromTrack = wi.getTrackForest().getTrackNode(waveEnv.getTrackAddress());
                        TrackNode.Echo echo = TrackNode.Echo.TRUE;
                        TrackCtrlMsg msg = new EchoMsg(fromTrack, echo, waveEnv);
                        wi.getTrackQueue().incoming(msg);
                    }
                    else if(!tail.equals("")){
                        Wave newWave = new Wave(tail, new WaveEnvironment(waveEnv));
                        waveQueue.incomingFront(newWave);
                    }
                    waveEnv.dump();
                    return;
                }
            }
            Vector vLeft=getLeft(caller);
            int size=vLeft.size();
            
//            if(caller.jjtGetChild(0) ){
//
//            }
            String funcName=getRight(caller);
            //funcName=funcName.substring(1, funcName.length()-1);
            Utilities.WPPrint("LEFT: " + vLeft + " RIGHT: " + funcName);

            String callFunc=new String();
            int offset= Integer.parseInt (vLeft.elementAt(0).toString());        
            
            if(offset==0){ // Loi goi lenh he thong
                callFunc="cmd /c ";
                //callFunc.concat(funcName);
                callFunc+=funcName;
            }else if(offset==1){ // Loi goi 1 class chua chay.
                callFunc="java -classpath ";        
                //Lay vao classpath
                String class_path="./class_to_run";
                        //(String)vLeft.elementAt(2);
                callFunc+=class_path;
                callFunc+=" ";
                callFunc+=funcName;

                // Lay tham so truyen vao cho class
                Iterator param=vLeft.iterator();
               
                int count=1;
                //Utilities.WPPrint("TEST BEGIN");
                while(param.hasNext())
                {
                    if(count<=2)
                    {
                        param.next();
                    }
                    else
                    {    callFunc+=" ";
                         callFunc+=param.next().toString();
                    }                    
                    count++;
                }              
            }else{
                // Truyen du lieu cho 1 tien trinh khac dang chay qua socket.
                try{
                    Socket socket = new Socket(InetAddress.getLocalHost(), 14188);
//                    BufferedReader br = new BufferedReader(
//                                new InputStreamReader(socket.getInputStream()));
                    PrintStream ps = new PrintStream(socket.getOutputStream());
                    Vector vectorInput= new Vector();
                    Object obj = new Object();

                    obj=vLeft.elementAt(2);
                    if (obj instanceof Collection){
                        vectorInput.addAll((Collection)obj);
                    }
                    else{
                        vectorInput.add(obj);
                    }
                    Iterator input= vectorInput.iterator();
                    while(input.hasNext()){                        
                        // Gửi msg ra socket
                        ps.println(input.next().toString());
                    }                   
//                    // Print response from server
//                    Utilities.WPPrint("Received: " + br.readLine());
                    socket.close();
                }catch (UnknownHostException ex) {
                      System.err.println(ex);
                }
                catch (IOException ex) {
                      System.err.println(ex);
                }
                callFunc="";
                vLeft.setElementAt("0", 1);
            }
            
            try {
                Utilities.WPPrint("Begining running system call ...\n" + funcName);
                Utilities.WPPrint(callFunc);
                Process p = Runtime.getRuntime().exec(callFunc);
                
                // Neu chuoi wave phải đợi, đợi chtrinh chạy xong,
                //              lưu lại giá trị vào biến ở vế trái của syscall
                if((Integer.parseInt (vLeft.elementAt(1).toString()))==1)
                {
                    BufferedReader in = new BufferedReader(
                                            new InputStreamReader(p.getInputStream()));

                    SimpleNode left = (SimpleNode)caller.jjtGetChild(0);
                    //SimpleNode l_left = (SimpleNode)left.jjtGetChild(0);


                    Vector v = new Vector();
                    String line=null;
                    v.add("Beginning of Output ");
                    while((line=in.readLine()) != null) {
                    // luu output ra bien
                        Utilities.WPPrint(line);
                        System.out.println(line);
                        v.add(line);
                    }

                    if (left instanceof ASTFrontalVar) {
                        Hashtable fTab = this.waveEnv.getFrontalTable();
                        Vector vt = (Vector)fTab.get(left.getString());

                        addToVector(vt, size+1, v);
                        Utilities.WPPrint(fTab);
                    }
                    else {
                        Hashtable nTab = this.kn.getKNNode(
                            this.waveEnv.getCONTENT()).getNodalTable(waveEnv.getColor());

                        Vector vt = (Vector)nTab.get(left.getString());

                        addToVector(vt,size+1, v);
                        Utilities.WPPrint(nTab);
                    }
                    p.waitFor();
                    in.close();
                }

                if (waveEnv.getTrackAddress() != null && (tail.equals("") )) {
                    TrackNode fromTrack = wi.getTrackForest().getTrackNode(waveEnv.getTrackAddress());
                    TrackNode.Echo echo =TrackNode.Echo.TRUE ;
                    //Tao message echo va gui vao TrackQueue
                    TrackCtrlMsg msg = new EchoMsg(fromTrack, echo, waveEnv);
                    wi.getTrackQueue().incoming(msg);
                }
                // Lay ra tail. Tao wave moi va cho vao wave queue
                else if(!tail.equals("")){
                    Wave newWave = new Wave(tail, new WaveEnvironment(waveEnv));
                    waveQueue.incomingFront(newWave);
                }
            } catch (IOException ex) {
                System.err.println("Problems invoking class " + funcName);
            }
            catch (InterruptedException ex)
            {
                System.err.print("Errors when .. exit ..");
            }


            Utilities.WPPrint("System call done");
           }        
    }

    /**
     * 
     * @param ASTSysCall caller
     * @return Vector left
     */
    public Vector getLeft(ASTSysCall caller){
        Vector v = new Vector();
        SimpleNode left = (SimpleNode) caller.jjtGetChild(0);

        Object obj = new Object();
        if(left instanceof ASTFrontalVar){
                obj = this.waveEnv.getFrontalTable().get(left.getString());
        } else if (left instanceof ASTNodalVar){
                obj = this.kn.getKNNode(this.waveEnv.getCONTENT()).
                        getNodalTable(waveEnv.getColor()).get(left.getString());
        }
        if (obj instanceof Collection){
            v.addAll((Collection)obj);
        } else {
            v.add(obj);
        }
        return v;
    }
    /**
     * 
     * @param ASTSysCall caller
     * @return String functionName
     */
    public String getRight(ASTSysCall caller)
    {       
        SimpleNode right=(SimpleNode) caller.jjtGetChild(1);

        String funcName =right.getString();
        return funcName;
    }

     public void addToVector(Vector vt, int index, Vector vt2) {
        if (index > 0 && index < (vt.size() + 1)) {
            for (int i=vt2.size()-1; i>=0; i-- ) {
                vt.add(index - 1, vt2.elementAt(i));
            }
            vt.remove(index + vt2.size() - 1);
        }
        else if (index == 0) {
            for (int i=vt2.size()-1; i>=0; i-- ) {
                vt.add(index, vt2.elementAt(i));
            }
        }
        else if (index == vt.size() + 1) {
            for (int i=0; i<vt2.size(); i++ ) {
                vt.add(vt2.elementAt(i));
            }
        }
    }
}
